/* * Demo of using clip2gif with the CFM PPC * * PLASE READ! * * This CGI program returns a GIF showing the trajectory of a planar parallel robot. * If should be saved as robot.acgi. It can be called with the following URLs: * * http://your.hostname/robot.acgi?k=h&w=5&h=7&n=10 * -> html page wrapping an image of a robot with a motion of width 20 * w, * height 10 * h, and 2 * n intermediate positions * (each argument is coded in 1 char :-( ) * * http://your.hostname/robot.acgi?k=g&w=20&h=30&n=10 * -> corresponding gif image * * To compile it, create a new PPC project with CW7 (other versions and compilers * might also work, but haven't been tested), include example-cgi.c, LoadClip2Gif.c, * InterfaceLib, MWCRuntime.Lib, MathLib and AppleScriptLib, and build it as "robot.acgi". * It should have at least canBackground and isHightLevelEventAware bits set. * Copy it anywhere in the HTTP server document tree. clip2gif should be on the same * volume, or in the same folder if there are former versions on the same volume. * * To quit robot.acgi, send it a quit AppleEvent ('tell app "robot.acgi" to quit' * in AppleScript), or type command-q. * *** Warning: The purpose of this CGI is *not* to show The Best Way to implement a CGI, *** but how simple it is to use clip2gif. * * Copyright 1995, Yves Piguet. All rights reserved. * * Can be distributed only as part of the whole clip2gif package. * * If you use this source code, acknowledgment on your web pages would be appreciated. * * Thanks! */ #include // math functions #include #include "LoadClip2Gif.h" int done; static StringPtr http_html_header = "\pHTTP/1.0 200 OK\r\n\Content-type: text/html\r\n\r\n"; static StringPtr http_gif_header = "\pHTTP/1.0 200 OK\r\nContent-type: image/gif\r\n\r\n"; static StringPtr http_error = "\pHTTP/1.0 400 ERROR\r\n\r\n"; // HTML doc. Not that nice to have it here in pascal strings, but you'd been warned. // The inline image URL can become robot.acgi?k=h&w=2&h=3&k=g or even // robot.acgi?&k=g , but it still works. static StringPtr html_t1 = "\p
Robot
\r\n

Robot

" "Planar parallel robot with horizontal tool base.

" "

New Move

" "
\r\n" "\r\n" "Width:

\r\n"; static StringPtr html_t4 = "\pHeight:

\r\n" "Intermediate positions:

\r\n" "

\r\n" "


CGI written by " "Yves Piguet
" "\r\n"; // some geometric constants #define iw 240 #define ih 200 #define top 5 #define ground 195 #define center 120 #define shoulder 20 #define arm 105 #define forearm 110 #define paralw 10 static void InitToolbox() { InitGraf((Ptr)&qd.thePort); InitFonts(); InitWindows(); InitMenus(); TEInit(); InitDialogs(0L); InitCursor(); } static pascal OSErr MyHandleQuit(AppleEvent *evt, AppleEvent *reply, long refCon) { #pragma unused(evt, reply, refCon) done = 1; return noErr; } static void DrawRobot(short a, short b) // draws the robot arms to point (a, b) over the ground { double x, y, tmp, x1, y1; short a1, b1; a1 = a - shoulder; b1 = ground - top - b; tmp = a1 * a1 + b1 * b1; x1 = (tmp + arm * arm - forearm * forearm) / (2 * tmp); y1 = sqrt(arm * arm / tmp - x1 * x1); x = a1 * x1 - b1 * y1; y = b1 * x1 + a1 * y1; MoveTo(center - shoulder, top); Line((short)x, (short)y); LineTo(center + a, ground - b); Line(paralw, 0); MoveTo(center - shoulder + (short)x, top + (short)y); Line(paralw, 0); MoveTo(center - shoulder + paralw, top); Line((short)x, (short)y); LineTo(center + a + paralw, ground - b); a1 = a + shoulder; tmp = a1 * a1 + b1 * b1; x1 = (tmp + arm * arm - forearm * forearm) / (2 * tmp); y1 = sqrt(arm * arm / tmp - x1 * x1); x = a1 * x1 + b1 * y1; y = b1 * x1 - a1 * y1; MoveTo(center + shoulder + paralw, top); Line((short)x, (short)y); LineTo(center + a + paralw, ground - b); } static pascal OSErr MyHandleSDOC(AppleEvent *evt, AppleEvent *reply, long refCon) { #pragma unused(refCon) Offscreen os; short width = 100, height = 40, n = 10, i; unsigned char kind = 'h'; DescType typeCode; Size actualSize; Str255 arg; AEDesc replyStr; Handle gifHandle; OSErr err; err = AEGetParamPtr(evt, 'kfor', typeChar, &typeCode, (Ptr)(arg + 1), 250, &actualSize); if (err != noErr) goto oops; arg[0] = actualSize; for (i = 0; i < arg[0] - 2; i++) if (arg[i + 2] == '=') switch (arg[i + 1]) { case 'k': case 'K': kind = arg[i + 3] | 32; // lowercase if (kind != 'g') kind = 'h'; arg[i + 2] = 'g'; // ready for the inline image URL break; case 'w': case 'W': if (arg[i + 3] >= '0' && arg[i + 3] <= '9') width = 20 * (arg[i + 3] - '0'); else width = 100; break; case 'h': case 'H': if (arg[i + 3] >= '0' && arg[i + 3] <= '9') height = 10 * (arg[i + 3] - '0'); else height = 40; break; case 'n': case 'N': if (arg[i + 3] >= '0' && arg[i + 3] <= '9') n = 2 * (arg[i + 3] - '0'); else n = 8; break; } if (kind == 'h') // HTML { replyStr.descriptorType = typeChar; err = PtrToHand((Ptr)(http_html_header + 1), &replyStr.dataHandle, http_html_header[0]); err = PtrAndHand((Ptr)(html_t1 + 1), replyStr.dataHandle, html_t1[0]); err = PtrAndHand((Ptr)(arg + 1), replyStr.dataHandle, arg[0]); // part of gif URL err = PtrAndHand((Ptr)(html_t2 + 1), replyStr.dataHandle, html_t2[0]); err = PtrAndHand((Ptr)(html_t3 + 1), replyStr.dataHandle, html_t3[0]); err = PtrAndHand((Ptr)(html_t4 + 1), replyStr.dataHandle, html_t4[0]); err = PtrAndHand((Ptr)(html_t5 + 1), replyStr.dataHandle, html_t5[0]); err = PtrAndHand((Ptr)(html_t6 + 1), replyStr.dataHandle, html_t6[0]); } else // GIF { err = BeginOffscreen(&os, iw, ih, 4, colorPaletteSystem); if (err != noErr) goto oops; // now the QuickDraw port is ok; we can draw directly PenSize(2, 2); // arms in the intermediate positions ForeColor(cyanColor); for (i = 1; i <= n; i++) DrawRobot(-width / 2 + width * i / (n + 1), height * i / (n + 1)); // arms in the extreme positions ForeColor(blackColor); DrawRobot(-width / 2, 0); DrawRobot(width / 2, height); // top (where the robot is fixed) ForeColor(redColor); PenSize(4, 4); MoveTo(0, top); Line(iw, 0); PenSize(1, 1); // that's it! //#ifdef noooooh { // if you want to check the image before launching your http server, // enable these lines and send robot.acgi the following AS command: // Çevent WWW½sdocÈ given Çclass kforÈ:"k=g&w=5&h=5&n=5" FSSpec spec; FSMakeFSSpec(0, 0, "\ptest.gif", &spec); (void)ConvertPixmapToGIFFile(os.pixmap, &spec, 1, transparencyFirstPixel); } //#endif err = ConvertPixmapToGIFHandle(os.pixmap, &gifHandle, 1, transparencyFirstPixel); if (err == noErr) // concat. the http GIF header and the gif { replyStr.descriptorType = typeChar; err = PtrToHand((Ptr)(http_gif_header + 1), &replyStr.dataHandle, http_gif_header[0]); err = HandAndHand(gifHandle, replyStr.dataHandle); DisposHandle(gifHandle); } (void)DisposeOffscreen(&os); } oops: if (err != noErr) { replyStr.descriptorType = typeChar; err = PtrToHand((Ptr)(http_error + 1), &replyStr.dataHandle, http_error[0]); } (void)AEPutParamDesc(reply, keyDirectObject, &replyStr); DisposHandle(replyStr.dataHandle); return noErr; } void main(void) { EventRecord myEvent; OSErr err; InitToolbox(); // standard stuff // uses the CFM to gain access to clip2gif exported functions err = LoadClip2Gif(); if (err != noErr) { SysBeep(1); // Cannot load clip2gif return; } // installs AppleEvent handlers for quit and sdoc (void)AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, NewAEEventHandlerProc(MyHandleQuit), 0L, 0); (void)AEInstallEventHandler('WWW½', 'sdoc', NewAEEventHandlerProc(MyHandleSDOC), 0L, 0); // main event loop for (done = 0; !done;) { WaitNextEvent(everyEvent, &myEvent, 30L, 0L); switch (myEvent.what) { case keyDown: if (myEvent.modifiers & cmdKey && (myEvent.message & charCodeMask) == 'q') // command-q -> quit done = 1; break; case kHighLevelEvent: (void)AEProcessAppleEvent(&myEvent); break; } } }